/*
 * test_bill.cpp
 *
 *  Created on: Feb 17, 2014
 *      Author: killerg
 */

#include <set>
#include <map>
#include <memory>
#include <string>
#include <queue>
#include <assert.h>
#include <getopt.h>

#include "share/http_c.h"
#include "share/util.h"

using namespace std;

// accounts -----------------------------------------------------
struct order_t {
	string orderId;
	int serverid = -1;
	string account;
	double payFee = 0.0f;
	string mc;
};
typedef shared_ptr<order_t> sp_order_t;

queue<sp_order_t> g_orders;
map<string, sp_order_t> g_dealt;

// workers -------------------------------------------------------
struct worker_t {
	http_client3 httpc3;

	int dealing = 0;
};
typedef shared_ptr<worker_t> sp_worker_t;

vector<sp_worker_t> g_workers;

int feeType[9] = { 5000, 2000, 1000, 500, 200, 100, 50, 30, 10 };
int serverId[3] = { 1, 1, 1 };

bool test_bill(int argc, char** argv) {
//	int serverid = -1;
//	std::string account = "";
//	double fee = 0.0f;
//	int opt;
//	while ((opt = getopt(argc, argv, "s:a:f:")) != -1) {
//		switch (opt) {
//		case 's':
//			serverid = atoi(optarg);
//			break;
//		case 'a':
//			account = optarg;
//			break;
//		case 'f':
//			fee = atof(optarg);
//			break;
//		}
//	}
//
//	if (serverid < 0) {
//		printf("invalid serverid\n");
//		return false;
//	}
//
//	if (account.empty()) {
//		printf("invalid account\n");
//		return false;
//	}
//
//	if (fee <= 0) {
//		printf("invalid fee\n");
//		return false;
//	}
//
//	http_client3 httpc;
//	if (!httpc.init()) {
//		printf("httpc init err\n");
//		return false;
//	}
//
//	Json::Value req_body;
//	req_body["orderId"] = 1234;
//	req_body["serverid"] = serverid;
//	req_body["account"] = account;
//	req_body["payFee"] = fee;
//	req_body["mc"] = account;
//
//	std::string query = to_cstr(req_body);
//	httpc.do_query(
//			"http://xone:8080/bill/au",
//			query.c_str(),
//			[](int code, const std::string& res){
//				if (code != CURLE_OK) {
//					printf("query err:%s\n", curl_easy_strerror(CURLcode(code)));
//					exit(1);
//				}
//				const Json::Value res_body = to_json(res);
//				if (res_body["errcode"].asInt() == 0) {
//					printf("success\n");
//					exit(0);
//				} else {
//					printf(
//							"errcode:%d errmsg:%s\n",
//							res_body["errcode"].asInt(),
//							res_body.get("errmsg", "").asCString()
//					);
//					exit(1);
//				}
//			});
//	while (true) {
//		httpc.update();
//		sleep(1);
//	}
//
//	httpc.destroy();
//
//	return true;

	int start = 30000;
//	for (int i = 0; i < 10000; ++i) {
//		auto order = make_shared<order_t>();
//		order->orderId = fmt_cstr("order-%d", start + i);
//		order->serverid = serverId[i % 3];
//		order->account = fmt_cstr("au-r%d", i % 5000);
//		order->payFee = feeType[i % 9];
//		order->mc = fmt_cstr("%lld", random(0, 5000));
//		g_orders.push(order);
//	}
//
	auto order = make_shared<order_t>();
	order->orderId = fmt_cstr("order-%d", 6);
	order->serverid = 1;
	order->account = "au-aaa";
	order->payFee = 100;
	order->mc = "12345";
	g_orders.push(order);


	for (int i = 0; i < 1; ++i) {
		auto worker = make_shared<worker_t>();
		bool ok = worker->httpc3.init();
		assert(ok);
		g_workers.push_back(worker);
	}

	while (true) {
		for (auto &worker : g_workers) {
			while (worker->dealing < 5 && !g_orders.empty()) {
				auto order = g_orders.front();
				g_orders.pop();

				Json::Value req_body;
				req_body["orderId"] = order->orderId;
				req_body["serverid"] = order->serverid;
				req_body["account"] = order->account;
				req_body["payFee"] = order->payFee;
				req_body["mc"] = order->mc;

				bool ok =
						worker->httpc3.do_query("http://xone:8080/bill/au",
								to_cstr(req_body),
								[order, worker](int code, const std::string& res) {
									--worker->dealing;
									if (CURLE_OK != code) {
										g_orders.push(order);
										return;
									}
									const Json::Value res_body = to_json(res);
									if (res_body["errcode"].asInt() == 0) {
										g_dealt.insert(make_pair(order->orderId, order));
									} else {
										printf(
												"order:%s account:%s fee:%f errcode:%d errmsg:%s\n",
												order->orderId.c_str(),
												order->account.c_str(),
												order->payFee,
												res_body["errcode"].asInt(),
												res_body.get("errmsg", "").asCString()
										);
									}

								});
				if (ok)
					++worker->dealing;
				else
					g_orders.push(order);
			}

			worker->httpc3.update();
		}
		sleep(1);
	}

	for (auto &worker : g_workers) {
		worker->httpc3.destroy();
	}
	g_workers.clear();

	return true;
}
